package com.study.designpattern.singleton;

/**
 * 懒汉式：解决{@link LazySingleton}遗留的加锁导致的性能问题。
 *
 * <p>
 * 双重检查锁模式是一种非常好的单例实现模式，解决了单例、性能、线程安全问题。
 * <p/>
 *
 * @author Anbang713
 */
public class DoubleDetectionSingleton {

  /**
   * 再说一遍，单例类的构造方法是私有的。
   */
  private DoubleDetectionSingleton() {
  }

  /**
   * 1、为避免在多线程的情况下，可能会出现空指针问题，出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。
   * 需要使用 {@code volatile} 关键字可以保证可见性和有序性。<br/>
   * 2、什么是指令重排序问题？是指对象被new出来，并且赋值给instance之后，还没来得及初始化（执行构造方法）就被另一个线程使用了。<br/>
   * 3、实际上只有很低的Java才会有这个问题，高版本的JDK内部实现已经解决了这个问题。
   */
  private static volatile DoubleDetectionSingleton instance;

  /**
   * @return 类的唯一对象
   */
  public static DoubleDetectionSingleton getInstance() {
    // 第一次判断，如果instance不为null，不进入抢锁阶段，直接返回实例
    if (instance == null) {
      synchronized (DoubleDetectionSingleton.class) {
        // 抢到锁之后再次判断是否为null
        if (instance == null) {
          instance = new DoubleDetectionSingleton();
        }
      }
    }
    return instance;
  }

  public static void main(String[] args) {
    DoubleDetectionSingleton obj1 = DoubleDetectionSingleton.getInstance();
    DoubleDetectionSingleton obj2 = DoubleDetectionSingleton.getInstance();

    System.out.println(obj1 == obj2);// 输出：true
  }
}
